package 回溯算法.N皇后;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

public class N皇后_51 {


    public static void main(String[] args) {
        System.out.println(new N皇后_51().solveNQueens(4));
    }


    //保存结果
    List<List<String>> res = new ArrayList<>();

    public List<List<String>> solveNQueens(int n) {
        char[][] board = new char[n][n];//棋盘
        //初始化棋盘
        for (char[] item : board) {
            Arrays.fill(item, '.');
        }
        backtrack(board, 0);
        return res;
    }

    /*
    路径：borad中小于row的哪些行都已经被放置了皇后，就相当于已经被选择过的列表
    选择列表：第row行中的所有列，都可以用来放置皇后
    结束条件：row超过board的最后一行，证明棋盘满了
    */
    public void backtrack(char[][] board, int row) {
        //触发了结束条件,直接把填好的棋盘放入res中
        if (row == board.length) {
            res.add(turn(board));
            return;//一定不能忘记，否则无法结束
        }

        int columns = board[0].length;
        for (int col = 0; col < columns; col++) {//遍历选择列表
            //排除不合法的选择
            if (!isValid(board, row, col)) {
                continue;
            }
            //把选择 加入到路径
            board[row][col] = 'Q';
            //进入下一行决策
            backtrack(board, row + 1);
            //撤销选择
            board[row][col] = '.';
        }
    }

    public boolean isValid(char[][] board, int row, int col) {
        int n = board.length;

        //看当前列是否已经有皇后了
        for (int i = 0; i < row; i++) {
            if (board[i][col] == 'Q') {
                return false;
            }
        }

        //检查右上方是否有皇后
        for (int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) {
            if (board[i][j] == 'Q') {
                return false;
            }
        }
        //检查左上方是否有皇后
        for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
            if (board[i][j] == 'Q') {
                return false;
            }
        }

        //我们不用检测当前行、列以下的棋盘，因为是从上往下开始填的
        return true;//没有冲突
    }

    /**
     * 用来做类型转换
     *
     * @param board
     * @return
     */
    public List<String> turn(char[][] board) {
        List<String> target = new LinkedList<>();
        for (char[] i : board) {
            StringBuffer sb = new StringBuffer();
            for (char j : i) {
                sb.append(j);
            }
            target.add(sb.toString());
        }
        return target;

    }
}
